/***************************************************************************
 *   This is a part of the NextCAD Web APP.                                *
 *   Copyright (C) AMCAX, All rights reserved.                             *
 ***************************************************************************/

import { pickedFaceData, pickedLineData, pickedVertexData } from '@amcax/base';
import { PickInputRJSFFormat } from '@app-cad/common/components/command-form/constants';
import { NonDialogPickableCommandForm } from '@app-cad/common/components/command-form/pickable';
import { useCommand } from '@app-cad/common/hooks/useCommand';
import { useTools } from '@app-cad/common/hooks/useTools';
import {
  DefaultLawCurveValue,
  getLawCurveFromJSONString,
  isLawCurveValid,
  LawCurve,
  LawCurveButton,
} from '@app-cad/common/law-curve';
import { getIdOfPickedObj } from '@app-cad/common/utils/render';
import { RJSFSchema } from '@rjsf/utils';
import { useAsyncEffect } from 'ahooks';
import { useEffect, useState } from 'react';
import { ChildCircleSweepCommandProps } from './type';

type FormData = {
  guide1?: pickedLineData;
  guide2?: pickedLineData;
  tangencySurface?: pickedFaceData;
  endGuide?: pickedLineData;
  endTangencySurface?: pickedFaceData;
  spline?: pickedLineData;
  leftBound?: pickedVertexData;
  rightBound?: pickedVertexData;
  jsonAngle1: string;
  jsonAngle2: string;
};

type Params = {
  mode: 'ThreeGuides';
  guide1: string;
  guide2: string;
  tangencySurface: string;
  endGuide: string;
  endTangencySurface: string;
  spline?: {
    id?: string;
    leftBound?: string;
    rightBound?: string;
  };
  lineLawAngle1: LawCurve;
  lineLawAngle2: LawCurve;
};

export function ThreeGuides({
  onClose,
  props,
  editDxid,
}: ChildCircleSweepCommandProps) {
  const initData: FormData = {
    jsonAngle1: DefaultLawCurveValue,
    jsonAngle2: DefaultLawCurveValue,
  };

  const [formData, setFormData] = useState<FormData>(initData);

  const schema: RJSFSchema = {
    type: 'object',
    properties: {
      guide1: {
        type: 'string',
        format: PickInputRJSFFormat.PickCurve,
      },
      tangencySurface: {
        type: 'string',
        format: PickInputRJSFFormat.PickSurface,
      },
      jsonAngle1: {
        title: '角度1',
        type: 'string',
      },
      guide2: {
        type: 'string',
        format: PickInputRJSFFormat.PickCurve,
      },
      endGuide: {
        type: 'string',
        format: PickInputRJSFFormat.PickCurve,
      },
      endTangencySurface: {
        type: 'string',
        format: PickInputRJSFFormat.PickSurface,
      },
      jsonAngle2: {
        title: '角度2',
        type: 'string',
      },
      spline: {
        type: 'string',
        format: PickInputRJSFFormat.PickCurve,
      },
      leftBound: {
        type: 'string',
        format: PickInputRJSFFormat.PickVertex,
      },
      rightBound: {
        type: 'string',
        format: PickInputRJSFFormat.PickVertex,
      },
    },
  };

  const { picker } = useTools();

  useEffect(() => {
    preview();
  }, [formData]);

  useAsyncEffect(async () => {
    if (props == null) {
      setFormData(initData);
      return;
    }
    const {
      guide1,
      guide2,
      tangencySurface,
      endGuide,
      endTangencySurface,
      spline,
      lineLawAngle1,
      lineLawAngle2,
    }: Params = props.params;

    await initEditDependency(
      [
        guide1,
        guide2,
        tangencySurface,
        endGuide,
        endTangencySurface,
        spline?.id,
        lineLawAngle1?.bsplineId,
        lineLawAngle2?.bsplineId,
      ].filter((id) => id != null),
    );

    setFormData({
      guide1: picker.generatePickObjByPickID(guide1) as pickedLineData,
      guide2: picker.generatePickObjByPickID(guide2) as pickedLineData,
      tangencySurface: picker.generatePickObjByPickID(
        tangencySurface,
      ) as pickedFaceData,
      endGuide: picker.generatePickObjByPickID(endGuide) as pickedLineData,
      endTangencySurface: picker.generatePickObjByPickID(
        endTangencySurface,
      ) as pickedFaceData,
      spline:
        spline?.id &&
        (picker.generatePickObjByPickID(spline?.id) as pickedLineData),
      leftBound:
        spline?.leftBound &&
        (picker.generatePickObjByPickID(spline?.leftBound) as pickedVertexData),
      rightBound:
        spline?.rightBound &&
        (picker.generatePickObjByPickID(
          spline?.rightBound,
        ) as pickedVertexData),
      jsonAngle1: JSON.stringify(lineLawAngle1),
      jsonAngle2: JSON.stringify(lineLawAngle2),
    });

    return;
  }, [editDxid]);

  const isFormDataValid = () => {
    const { guide1, guide2, tangencySurface, endGuide, endTangencySurface } =
      formData;
    const angleValid1 = isLawCurveValid(formData.jsonAngle1);
    const angleValid2 = isLawCurveValid(formData.jsonAngle2);
    return (
      angleValid1 &&
      angleValid2 &&
      guide1 != null &&
      guide2 != null &&
      tangencySurface != null &&
      endGuide != null &&
      endTangencySurface != null
    );
  };

  const checkAndFinishDraw = async () => {
    if (!isFormDataValid()) {
      return;
    }

    await execute(false);
    onClose();
  };

  const { initEditDependency, initingEdit, clear, confirmCommand, isLoading } =
    useCommand('cmd-conic-sweep-tow-guides', {
      commandName: 'CreateSurface',
      editDxid: props?.shape,
      onClose,
      finishDraw: checkAndFinishDraw,
    });

  const execute = (preview: boolean) => {
    return confirmCommand(
      {
        type: 'ConicalSweep',
        a: {
          mode: 'ThreeGuides',
          guide1: getIdOfPickedObj(formData.guide1),
          guide2: getIdOfPickedObj(formData.guide2),
          tangencySurface: getIdOfPickedObj(formData.tangencySurface),
          endGuide: getIdOfPickedObj(formData.endGuide),
          endTangencySurface: getIdOfPickedObj(formData.endTangencySurface),
          spline: {
            id: formData.spline?.edgeId
              ? formData.spline?.edgeId
              : getIdOfPickedObj(formData.guide1),
            leftBound: formData.leftBound?.vertexId,
            rightBound: formData.rightBound?.vertexId,
          },
          lineLawAngle1: getLawCurveFromJSONString(formData.jsonAngle1),
          lineLawAngle2: getLawCurveFromJSONString(formData.jsonAngle2),
        } as Params,
      },
      preview,
    );
  };

  const preview = async () => {
    if (!isFormDataValid()) {
      clear();
      return;
    }

    execute(true);
  };

  return (
    <NonDialogPickableCommandForm
      disabled={initingEdit}
      className='-mt-3'
      onCancel={onClose}
      schema={schema}
      submitLoading={isLoading}
      formData={formData}
      onChange={(v) => {
        setFormData(v);
      }}
      submitText='完成'
      onSubmit={checkAndFinishDraw}
      extraUiSchema={{
        guide1: {
          'ui:autofocus': true,
          'ui:placeholder': '请输入引导曲线1',
        },
        guide2: {
          'ui:placeholder': '请输入引导曲线2',
        },
        endGuide: {
          'ui:placeholder': '请输入结束引导曲线',
        },
        tangencySurface: {
          'ui:placeholder': '请输入相切曲面',
          'ui:options': {
            allowInfinitePlane: true,
          },
        },
        endTangencySurface: {
          'ui:placeholder': '请输入结束相切曲面',
          'ui:options': {
            allowInfinitePlane: true,
          },
        },
        jsonAngle1: {
          'ui:widget': LawCurveButton,
          'ui:options': {
            suffix: '度',
          },
        },
        jsonAngle2: {
          'ui:widget': LawCurveButton,
          'ui:options': {
            suffix: '度',
          },
        },
        spline: {
          'ui:placeholder': '脊线(默认是引导线)',
        },
        leftBound: {
          'ui:placeholder': '��界1(选填)',
        },
        rightBound: {
          'ui:placeholder': '边界2(选填)',
        },
      }}
      isFormDataValid={isFormDataValid()}
    />
  );
}
